using System;
using System.Runtime.InteropServices;

namespace WindowsAPI.Hardware
{
    internal class Temp
    {
        //
        // http://www.codeproject.com/KB/cs/HardwareHelper.aspx
        //
        //Name:     ChangeIt
        //Inputs:   pointer to hdev, SP_DEV_INFO, bool
        //Outputs:  bool
        //Errors:   This method may throw the following exceptions.
        //      Unable to change device state!
        //Remarks:  Attempts to enable or disable a device driver.  
        //      IMPORTANT NOTE!!!   This code currently does not check the reboot flag.
        //      =================   Some devices require you reboot the OS for the change
        //                  to take affect.  If this describes your device, you 
        //                  will need to look at the SDK call:
        //                  SetupDiGetDeviceInstallParams.  You can call it 
        //                  directly after ChangeIt to see whether or not you need 
        //                  to reboot the OS for you change to go into effect.
        public bool ChangeIt(IntPtr hDevInfo, SP_DEVINFO_DATA devInfoData, bool bEnable)
        {
            try
            {
                //Marshalling vars
                int szOfPcp;
                IntPtr ptrToPcp;
                int szDevInfoData;
                IntPtr ptrToDevInfoData;

                var pcp = new SP_PROPCHANGE_PARAMS();
                if(bEnable)
                {
                    pcp.ClassInstallHeader.cbSize = Marshal.SizeOf(typeof(SP_CLASSINSTALL_HEADER));
                    pcp.ClassInstallHeader.InstallFunction = DIF.PropertyChange;
                    pcp.StateChange = DICS.Enable;
                    pcp.Scope = DICS_FLAG.Global;
                    pcp.HwProfile = 0;

                    //Marshal the params
                    szOfPcp = Marshal.SizeOf(pcp);
                    ptrToPcp = Marshal.AllocHGlobal(szOfPcp);
                    Marshal.StructureToPtr(pcp, ptrToPcp, true);
                    szDevInfoData = Marshal.SizeOf(devInfoData);
                    ptrToDevInfoData = Marshal.AllocHGlobal(szDevInfoData);

                    if(SetupAPI.SetupDiSetClassInstallParams(
                                                             hDevInfo, ptrToDevInfoData, ptrToPcp, Marshal.SizeOf(typeof(SP_PROPCHANGE_PARAMS))))
                    {
                        SetupAPI.SetupDiCallClassInstaller(DIF.PropertyChange, hDevInfo, ptrToDevInfoData);
                    }
                    pcp.ClassInstallHeader.cbSize = Marshal.SizeOf(typeof(SP_CLASSINSTALL_HEADER));
                    pcp.ClassInstallHeader.InstallFunction = DIF.PropertyChange;
                    pcp.StateChange = DICS.Enable;
                    pcp.Scope = DICS_FLAG.ConfigSpecific;
                    pcp.HwProfile = 0;
                }
                else
                {
                    pcp.ClassInstallHeader.cbSize = Marshal.SizeOf(typeof(SP_CLASSINSTALL_HEADER));
                    pcp.ClassInstallHeader.InstallFunction = DIF.PropertyChange;
                    pcp.StateChange = DICS.Disable;
                    pcp.Scope = DICS_FLAG.ConfigSpecific;
                    pcp.HwProfile = 0;
                }
                //Marshal the params
                szOfPcp = Marshal.SizeOf(pcp);
                ptrToPcp = Marshal.AllocHGlobal(szOfPcp);
                Marshal.StructureToPtr(pcp, ptrToPcp, true);
                szDevInfoData = Marshal.SizeOf(devInfoData);
                ptrToDevInfoData = Marshal.AllocHGlobal(szDevInfoData);
                Marshal.StructureToPtr(devInfoData, ptrToDevInfoData, true);

                var rslt1 = SetupAPI.SetupDiSetClassInstallParams(hDevInfo, ptrToDevInfoData,
                                                                  ptrToPcp, Marshal.SizeOf(typeof(SP_PROPCHANGE_PARAMS)));
                var rstl2 = SetupAPI.SetupDiCallClassInstaller(DIF.PropertyChange, hDevInfo, ptrToDevInfoData);
                if((!rslt1) || (!rstl2))
                    throw new ApplicationException("Unable to change device state!");
                return true;
            }
            catch(Exception)
            {
                return false;
            }
        }
    }
}